from sqlalchemy.orm import Session
from sqlalchemy import update
from . import models, schemas
from datetime import datetime
from domain.response import success, error
from constant.admin_constants import *
from utils import snowflaker

from sys import version

import sqlalchemy
from sqlalchemy.orm import Session
from sqlalchemy.sql.selectable import _OffsetLimitParam
from sqlalchemy.sql.util import _offset_or_limit_clause
from . import models, schemas
from typing import Optional, List


# @付康
# 模板可参考crud.py

def version2int(version):
    vi = 0
    for i, v in enumerate(version.split('.')):
        vi += int(v) * 10 ** (6 - 2 * i)
    return vi


async def get_version_by_condition(db: Session,
                                   platform: Optional[str] = None,  # 选择平台(android/ios)升级
                                   update_version_code: Optional[str] = None,  # 选择制定版本进行升级（有的话将最大版本号最小版本号同时设置为此值）
                                   max_update_version_code: Optional[str] = None,  # 选择可升级的最大版本号进行升级（默认所有中的最大值）
                                   min_update_version_code: Optional[str] = None,  # 选择可升级的最小版本号进行升级（默认所有中的最小值）
                                   max_os_api: Optional[int] = None,  # 选择支持的最大操作系统版本进行升级（默认所有中的最大值）
                                   min_os_api: Optional[int] = None,  # 选择支持的最小操作系统版本进行升级（默认所有中的最大值）
                                   cpu_arch: Optional[str] = None,  # 选择CPU架构进行升级
                                   channel: Optional[str] = None,  # 选择不同应用商店进行升级
                                   page: Optional[int] = 1,  # 选择第几页
                                   page_number: Optional[int] = 10,  # 选择每页的版本信息数量
                                   ) -> List[models.Version]:
    result = db.query(models.Version)
    if update_version_code:
        result = result.filter(models.Version.version == version2int(update_version_code))
    if max_update_version_code:
        result = result.filter(models.Version.version <= version2int(max_update_version_code))
    if min_update_version_code:
        result = result.filter(models.Version.version >= version2int(min_update_version_code))
    if max_os_api:
        result = result.filter(models.Version.max_os_api <= int(max_os_api))
    if min_os_api:
        result = result.filter(models.Version.min_os_api >= int(min_os_api))
    if platform:
        result = result.filter(models.Version.platform == platform)
    if cpu_arch:
        result = result.filter(models.Version.cpu_arch == cpu_arch)
    if channel:
        result = result.filter(models.Version.channel == channel)
    return result.order_by(models.Version.version.desc()).offset((page - 1) * page_number).limit(page_number).all()


async def get_version_count(db: Session,
                            platform: Optional[str] = None,  # 选择平台(android/ios)升级
                            update_version_code: Optional[str] = None,  # 选择制定版本进行升级（有的话将最大版本号最小版本号同时设置为此值）
                            max_update_version_code: Optional[str] = None,  # 选择可升级的最大版本号进行升级（默认所有中的最大值）
                            min_update_version_code: Optional[str] = None,  # 选择可升级的最小版本号进行升级（默认所有中的最小值）
                            max_os_api: Optional[int] = None,  # 选择支持的最大操作系统版本进行升级（默认所有中的最大值）
                            min_os_api: Optional[int] = None,  # 选择支持的最小操作系统版本进行升级（默认所有中的最大值）
                            cpu_arch: Optional[str] = None,  # 选择CPU架构进行升级
                            channel: Optional[str] = None,  # 选择不同应用商店进行升级
                            page: Optional[int] = 1,  # 选择第几页
                            page_number: Optional[int] = 10,  # 选择每页的版本信息数量
                            ) -> int:
    result = db.query(sqlalchemy.func.count(models.Version.bid))
    if update_version_code:
        result = result.filter(models.Version.version == version2int(update_version_code))
    if max_update_version_code:
        result = result.filter(models.Version.version <= version2int(max_update_version_code))
    if min_update_version_code:
        result = result.filter(models.Version.version >= version2int(min_update_version_code))
    if max_os_api:
        result = result.filter(models.Version.max_os_api <= int(max_os_api))
    if min_os_api:
        result = result.filter(models.Version.min_os_api >= int(min_os_api))
    if platform:
        result = result.filter(models.Version.platform == platform)
    if cpu_arch:
        result = result.filter(models.Version.cpu_arch == cpu_arch)
    if channel:
        result = result.filter(models.Version.channel == channel)
    return result.scalar()


async def get_versions_by_page(db: Session,
                               page: Optional[int] = 1,
                               page_number: Optional[int] = 20):
    version = db.query(models.Version).offset(page).limit(page_number)
    return version.all()


# @张寒萌
# 模板可参考crud.py
async def get_version(bid: str, db: Session):
    return db.query(models.Version).filter(models.Version.bid == bid).first()


async def open_version(bid: str, msg: str, db: Session):
    # get version
    version = db.query(models.Version).filter(models.Version.bid == bid).first()
    # has been deleted
    if version.is_delete == 1:
        return
    # set open
    version.is_release = 1
    # add a message
    # todo: bid & user_bid
    workerValue = snowflaker.IdWorker(1, 2, 0).get_id()
    bid = "V" + str(workerValue)
    version_msg = models.VersionMessage(bid=bid, version_bid=bid, operation=OPEN_VERSION, user_bid='', content=msg,
                                        create_time=datetime.now())
    db.add(version_msg)
    db.commit()
    return version


async def close_version(bid: str, msg: str, db: Session):
    # get version
    version = db.query(models.Version).filter(models.Version.bid == bid).first()
    # has been deleted
    if version.is_delete == 1:
        return
    # set close
    version.is_release = 0
    # add a message
    # todo: bid & user_bid
    version_msg = models.VersionMessage(bid='', version_bid=bid, operation=4, user_bid='', content=msg,
                                        create_time=datetime.now())
    db.add(version_msg)
    db.commit()
    return version


async def delete_version(bid: str, msg: str, db: Session):
    # get version
    version = db.query(models.Version).filter(models.Version.bid == bid).first()
    # has been deleted
    if version.is_delete == 1:
        return
    # set deleted and add delete time
    version.is_release = 0
    version.delete_time = datetime.now()
    # add a message
    version_msg = models.VersionMessage(bid='', version_bid=bid, operation=3, user_bid='', content=msg,
                                        create_time=datetime.now())
    db.add(version_msg)
    db.commit()
    return version


def version_str2int(vstr: str):
    vint = 0
    cnt = 4

    for v in vstr.split('.'):
        vint = vint * 10 ** 2 + int(v)
        cnt -= 1

    for i in range(cnt):
        vint *= 10 ** 2

    return vint


async def add_version(bid: str, version: schemas.VersionCreate, msg: str, db: Session):
    version_new = models.Version(bid=version.bid, version=version_str2int(version.version), md5=version.md5,
                                 download_url=version.download_url, max_os_api=version.max_os_api,
                                 min_os_api=version.min_os_api, max_version=version_str2int(version.max_version),
                                 min_version=version_str2int(version.min_version),
                                 cpu_arch=version.cpu_arch, channel=version.channel, pop_count=0, install_count=0,
                                 create_time=datetime.now(), delete_time=None, is_delete=0, is_release=0)
    # add a version
    db.add(version_new)
    # add a message
    version_msg = models.VersionMessage(bid='', version_bid=version.bid, operation=1, user_bid='', content=msg,
                                        create_time=datetime.now())
    db.add(version_msg)
    db.commit()
    return version_new


async def update_version(version: schemas.VersionCreate, msg: str, db: Session):
    # get version
    version_update = db.query(models.Version).filter(models.Version.bid == version.bid).first()

    # has been deleted
    if version_update.is_delete == 1:
        return error(code=41001, msg='This version has been deleted!')

    # is online
    if version_update.is_release == 1:
        return error(code=41011, msg='This version has been open!')

    # update a version
    version_update.version = version_str2int(version.version)
    version_update.md5 = version.md5
    version_update.download_url = version.download_url
    version_update.max_os_api = version.max_os_api
    version_update.min_os_api = version.min_os_api
    version_update.max_version = version_str2int(version.max_version)
    version_update.min_version = version_str2int(version.min_version)
    version_update.cpu_arch = version.cpu_arch
    version_update.channel = version.channel

    # add a message
    version_msg = models.VersionMessage(bid='', version_bid=version.bid, operation=2, user_bid='', content=msg,
                                        create_time=datetime.now())
    db.add(version_msg)
    db.commit()
    return version_update
